﻿using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Reflection;

namespace Common.Helper
{
    /// <summary>
    /// 枚举工具帮助类
    /// 支持：数字转枚举文本（默认名称/自定义属性）、文本转枚举数字（匹配名称/自定义属性）
    /// </summary>
    public static class EnumHelper
    {
        /// <summary>
        /// 缓存结构：Key=枚举类型, Value=枚举成员元数据（包含值、名称、自定义属性文本）
        /// </summary>
        private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<object, EnumMemberMeta>>
            _enumMetaCache = new ConcurrentDictionary<Type, ConcurrentDictionary<object, EnumMemberMeta>>();

        /// <summary>
        /// 枚举成员元数据模型
        /// </summary>
        private class EnumMemberMeta
        {
            /// <summary>
            /// 枚举的原始值（数字）
            /// </summary>
            public object Value { get; set; }

            /// <summary>
            /// 枚举的默认名称（如：Enable）
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 枚举的自定义属性文本（如 DisplayName/Description，无则为null）
            /// </summary>
            public string CustomText { get; set; }
        }

        /// <summary>
        /// 判断指定对象是否为枚举类型实例
        /// </summary>
        /// <param name="value">待判断的对象</param>
        /// <returns>如果是枚举类型实例则返回true，否则返回false（包括null的情况）</returns>
        public static bool IsEnum(object value)
        {
            // 处理null的情况（null不是任何类型的实例）
            if (value == null)
                return false;

            // 获取对象的类型，检查是否为枚举类型
            return value.GetType().IsEnum;
        }

        /// <summary>
        /// 非泛型版本：根据枚举值（object）获取枚举文本
        /// 支持自定义属性（如DisplayName/Description），优先返回自定义文本，无则返回枚举名称
        /// </summary>
        /// <param name="enumValue">枚举值（必须是枚举类型的实例，如：StatusEnum.Enable）</param>
        /// <param name="customAttrType">自定义属性类型（如：typeof(DisplayNameAttribute)，默认自动识别）</param>
        /// <returns>枚举文本（自定义属性文本或枚举名称）</returns>
        /// <exception cref="ArgumentException">参数不是枚举类型或值无效</exception>
        public static string GetEnumTextByValue(object enumValue, Type customAttrType = null)
        {
            // 1. 基础参数校验
            if (enumValue == null)
                throw new ArgumentNullException(nameof(enumValue), "枚举值不能为null");

            Type enumType = enumValue.GetType();
            // 校验是否为枚举类型
            if (!enumType.IsEnum)
                throw new ArgumentException($"参数[{nameof(enumValue)}]必须是枚举类型，实际类型：{enumType.FullName}");

            // 校验枚举值是否有效（如：数字3不在枚举[0,1,2]范围内）
            if (!Enum.IsDefined(enumType, enumValue))
                throw new ArgumentException($"枚举类型[{enumType.Name}]中不存在值[{enumValue}]");

            // 2. 处理自定义属性类型（默认使用DisplayNameAttribute）
            customAttrType ??= typeof(DisplayNameAttribute);

            // 3. 获取枚举元数据（从缓存或初始化）
            var enumMeta = GetOrInitEnumMeta(enumType, customAttrType)[enumValue];

            // 4. 优先返回自定义属性文本，无则返回枚举名称
            return string.IsNullOrEmpty(enumMeta.CustomText) ? enumMeta.Name : enumMeta.CustomText;
        }

        // 非泛型版本：获取或初始化枚举元数据（复用缓存逻辑）
        private static ConcurrentDictionary<object, EnumMemberMeta> GetOrInitEnumMeta(Type enumType, Type customAttrType)
        {
            // 1. 尝试从缓存获取
            if (_enumMetaCache.TryGetValue(enumType, out var existingMetaDict))
                return existingMetaDict;

            // 2. 初始化枚举元数据（反射获取所有成员）
            var metaDict = new ConcurrentDictionary<object, EnumMemberMeta>();
            var enumMembers = enumType.GetMembers(BindingFlags.Public | BindingFlags.Static);

            foreach (var member in enumMembers)
            {
                // 获取枚举成员的原始值（如：StatusEnum.Enable的值=1）
                object enumValue = Enum.Parse(enumType, member.Name);
                // 获取自定义属性文本（如：DisplayNameAttribute的文本）
                string customText = GetEnumMemberCustomText(member, customAttrType);

                metaDict.TryAdd(enumValue, new EnumMemberMeta
                {
                    Value = enumValue,
                    Name = member.Name,
                    CustomText = customText
                });
            }

            // 3. 缓存元数据（线程安全）
            _enumMetaCache.TryAdd(enumType, metaDict);
            return metaDict;
        }

        /// <summary>
        /// 获取枚举成员的自定义属性文本（如：DisplayName/Description）
        /// </summary>
        private static string GetEnumMemberCustomText(MemberInfo member, Type customAttrType)
        {
            // 1. 获取成员上的自定义属性实例
            var attr = member.GetCustomAttribute(customAttrType);
            if (attr == null)
                return null;

            // 2. 读取属性的“文本值”（约定：自定义属性需有公开的文本属性，如DisplayName/Description）
            var textProperty = customAttrType.GetProperty(
                nameof(DisplayNameAttribute.DisplayName), // 优先匹配DisplayName
                BindingFlags.Public | BindingFlags.Instance);

            // 若没有DisplayName，尝试匹配Description（兼容DescriptionAttribute）
            textProperty ??= customAttrType.GetProperty(
                nameof(DescriptionAttribute.Description),
                BindingFlags.Public | BindingFlags.Instance);

            // 3. 若属性不存在，返回null
            return textProperty?.GetValue(attr)?.ToString();
        }
    }
}